/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pigx.user.service.impl;

import cn.hutool.crypto.symmetric.AES;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.enums.AbnormalEnum;
import com.pig4cloud.pigx.common.customize.enums.CommonDictEnum;
import com.pig4cloud.pigx.common.customize.exception.DuckweedException;
import com.pig4cloud.pigx.common.customize.mysql.utils.MysqlUtil;
import com.pig4cloud.pigx.common.customize.redis.constants.RedisKeyEnum;
import com.pig4cloud.pigx.common.customize.redis.utils.RedisUtils;
import com.pig4cloud.pigx.common.customize.utils.id.IdWorker;
import com.pig4cloud.pigx.user.constant.RedisKeyPrefixConstant;
import com.pig4cloud.pigx.user.constant.WalletConstant;
import com.pig4cloud.pigx.user.entity.TimingConfig;
import com.pig4cloud.pigx.user.mapper.TimingConfigMapper;
import com.pig4cloud.pigx.user.service.TimingConfigService;
import com.pig4cloud.pigx.user.util.CronUtils;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;

/**
 * 归集相关定时任务配置
 *
 * @author pigx code generator
 * @date 2022-12-15 15:44:52
 */
@Service
@AllArgsConstructor
@Component
public class TimingConfigServiceImpl extends ServiceImpl<TimingConfigMapper, TimingConfig> implements TimingConfigService {

	private final IdWorker idWorker;
	private final RedisUtils redisUtils;
	private final MysqlUtil mysqlUtil;
	private final RedisTemplate redis;
	@Override
	public R<String> saveConfig(List<TimingConfig> list) {
		try {
			mysqlUtil.startLocalTx();
			for (TimingConfig config : list) {
				// 如果传入私钥,则对私钥进行加密
				if (config.getPrivateKey() != null && !config.getPrivateKey().isEmpty()) {
					AES aes = new AES(WalletConstant.AES_KEY);
					String uscAesPrivateKey = aes.encryptBase64(config.getPrivateKey(), Charset.defaultCharset());
					config.setPrivateKey(uscAesPrivateKey);
				}
				if (config.getId() != null) {
					if (config.getPrivateKey() != null && config.getPrivateKey().isEmpty()) {
						config.setPrivateKey(null);
					}
					config.updateById();
				} else {
					config.setId(idWorker.nextId());
					config.insert();
				}
				// 更新redis缓存
				redisUtils.flushPersistentCache(RedisKeyEnum.TIMING_CONFIG, config.getType(), config);
				if (config.getTimingPeriod() != null && !config.getTimingPeriod().isEmpty()) {
					nextTimeChange(config);
				}
			}
			mysqlUtil.commitLocalTx();
			return R.ok();
		} catch (Exception e) {
			mysqlUtil.rollbackLocalTx();
			throw new DuckweedException(AbnormalEnum.MSG.DISCONNECTED.getCode(),"配置保存失败");
		}
	}

	@Override
	public R<List<TimingConfig>> getConfigList() {
		List<TimingConfig> configs = new TimingConfig().selectList(null);
		for (TimingConfig config : configs) {
			config.setPrivateKey(null);
		}
		return R.ok(configs);
	}

	@Override
	public void nextTimeChange(TimingConfig config) {
		String key = RedisKeyPrefixConstant.TIMING_RUNNER_TIME + config.getType();
		// 停用状态直接删除已有任务节点
		if (config.getStatus().equals(CommonDictEnum.Status.DEPRECATED.getValue())) {
			if (Boolean.TRUE.equals(redis.hasKey(key))) {
				redis.delete(key);
				return;
			}
		}
		// 根据cron表达式获取下一次执行时间
		Date date;
		try {
			date = CronUtils.nextTime(config.getTimingPeriod(), new Date());
		} catch (Exception e) {
			throw new DuckweedException(AbnormalEnum.MSG.UNKNOWN_ORDER_COMPOSITION.getCode(),"cron表达式异常");
		}
		// 缓存入redis
		redis.opsForValue().set(key,CronUtils.dateToLocalDateTime(date));
	}

}
